package com.itxuhang.spring.factory;

import com.itxuhang.spring.aware.Aware;
import com.itxuhang.spring.aware.BeanFactoryAware;
import com.itxuhang.spring.init.InitializingBean;
import com.itxuhang.spring.po.BeanDefinition;
import com.itxuhang.spring.po.PropertyValue;
import com.itxuhang.spring.resolver.BeanDefinitionValueResolver;
import com.itxuhang.spring.utils.ReflectUtils;

import java.util.List;

/**
 * 该类具体负责创建Bean对象的事情
 */
public abstract class AbstractAutowiredCapableBeanFactory  extends  AbstractBeanFactory{

    @Override
    public Object createBean(BeanDefinition bd) {
        //    5.1 利用反射创建出来对象实例
        Object bean = createInstance(bd);
        //    5.2 利用反射对创建出来的对象进行属性赋值
        populateBean(bean,bd);
        //    5.3 利用反射调用Bean对象的初始化方法
        initilizingBean(bean,bd);
        return bean;
    }

    private void initilizingBean(Object bean, BeanDefinition bd) {
        // 判断bean是否实现了Aware接口
        if (bean instanceof Aware){
            if (bean instanceof BeanFactoryAware){
                ((BeanFactoryAware)bean).setBeanFactory(this);
            }
        }

        // 初始化方法的调用方式1
        if(bean instanceof InitializingBean){
            ((InitializingBean)bean).afterPropertiesSet();
        }

        // 初始化方法的调用方式2
        String initMethod = bd.getInitMethod();
        if (initMethod == null || initMethod.equals("")){
            return;
        }
        ReflectUtils.invokeMethod(bd.getClazzType(),bean,initMethod);
    }

    private void populateBean(Object bean, BeanDefinition bd) {
        List<PropertyValue> propertyValues = bd.getPropertyValues();

        BeanDefinitionValueResolver resolver = new BeanDefinitionValueResolver(this);
        for (PropertyValue pv : propertyValues) {
            // 获取属性名
            String name = pv.getName();
            // 获取属性值（这不是最终要的属性值）
            Object value = pv.getValue();

            Object valueToUse = resolver.parseValue(value);

            // 依赖注入
            ReflectUtils.setProperty(bd.getClazzType(),bean,name,valueToUse);
        }
    }

    private Object createInstance(BeanDefinition bd) {
        // 具体创建Bean可以通过反射创建，其实也可以通过静态工厂方法，获取工厂实力方法去创建
        return ReflectUtils.newInstance(bd.getClazzType());
    }

}
